import jwt
import time
from django.conf import settings
from rest_framework.authentication import BaseAuthentication, get_authorization_header
from rest_framework import exceptions
from jwt.exceptions import ExpiredSignatureError
from .models import OAUser


# 生成 JWT 的函数
# 用于验证 JWT 的两个自定义认证类

def generate_jwt(user):
    # 生成JWT  计算过期时间（当前时间 + 7 天）。
    expire_time = time.time() + 60 * 60 * 24 * 7 # JWT 过期时间为7天
    # 使用 jwt.encode 方法生成一个包含用户 ID（userid）和过期时间（exp）的 JWT，使用 settings.SECRET_KEY 作为密钥进行加密。
    # 返回生成的JWT。
    return jwt.encode({"userid": user.pk, "exp": expire_time}, key=settings.SECRET_KEY) # 返回JWT

# 功能：直接返回请求对象上的用户和认证信息。
class UserTokenAuthentication(BaseAuthentication):
    # 直接返回请求对象上的用户和认证信息。
    def authenticate(self, request):  # *** 重写authenticate方法
        # 直接从原始请求对象 _request 上获取用户和认证信息。
        # 这里的request：是rest_framework.request.Request对象
        # 返回用户和认证信息。
        # 在 Django REST framework 的 Request 对象中，_request 属性指向了 Django 的 HttpRequest 对象，
        # 所以可以通过 request._request.user 来访问请求中的用户。
        # request._request.auth 则是请求中的认证信息。
        return request._request.user, request._request.auth


# 功能：从请求中提取并验证 JWT，绑定用户信息到请求对象上。
class JWTAuthentication(BaseAuthentication):
    # 从请求头中获取 Authorization    信息并拆分。
    keyword = 'JWT'
    def authenticate(self, request):  # *** 重写authenticate方法
        # 检查请求头是否为空或是否以 JWT 开头（区分大小写）
        auth = get_authorization_header(request).split()# 获取请求头中的 Authorization 信息并拆分 []
        if not auth or auth[0].lower() != self.keyword.lower().encode():
            # 如果不满足条件，返回 None。
            return None
        # 如果满足条件，则继续执行。
        if len(auth) == 1: # 如果长度为1，说明没有提供 JWT Token
            msg = "不可用的JWT请求头！"
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2: # 如果长度大于2，说明JWT Token中间有空格
            msg = '不可用的JWT请求头！JWT Token中间不应该有空格！'
            raise exceptions.AuthenticationFailed(msg)
        try:
            jwt_token = auth[1] # 获取JWT Token
            jwt_info = jwt.decode(jwt_token, settings.SECRET_KEY, algorithms='HS256')
            userid = jwt_info.get('userid') #   获取JWT Token中的用户ID
            try:
                # 绑定当前user到request对象上
                user = OAUser.objects.get(pk=userid)
                setattr(request, 'user', user) #    将用户绑定到request对象上
                return user, jwt_token
            except:
                msg = '用户不存在！'
                raise exceptions.AuthenticationFailed(msg)
        except ExpiredSignatureError:
            msg = "JWT Token已过期！"
            raise exceptions.AuthenticationFailed(msg)
